// 1、插件， 挂载 $store
// 2、实现 Store

let Vue
class Store {
  constructor (options) {
    // 保存 mutation 和 action
    this._mutations = options.mutations
    this._actions = options.actions
    this._wrappedGetters = options.getters

    // 定义 computed 选项
    const computed = {}
    // 遍历传入的 getters，将 key 响应式的设置到 this.gettters 中
    // 通过 key 做代理
    this.getters = {}
    const store = this
    Object.keys(this._wrappedGetters).forEach(key => {
      // 获取用户定义的getter
      const fn = store._wrappedGetters[key]
      // 转换为computed可以使用无参数形式
      computed[key] = function () {
        return fn(store.state)
      }
      Object.defineProperty(store.getters, key, {
        get: () => {
          return store._vm[key]
        }
      })
    })

    // 绑定 this 为 store 执行
    this.commit = this.commit.bind(this)
    this.dispatch = this.dispatch.bind(this)
    // this.getters = this.getters.bind(this)

    // data 响应式，将 state 隐藏在 _vm._data.$$state 下
    this._vm = new Vue({
      data: {
        $$state: options.state
      },
      computed
    })
  }

  // 做转发
  get state () {
    return this._vm._data.$$state
  }

  // 不可直接set
  set state (v) {
    console.error('please use commit')
  }

  // commit
  commit (type, payload) {
    const entry = this._mutations[type]
    if (!entry) {
      console.error('unknow mutation type')
    }
    entry(this.state, payload)
  }

  // dispatch
  dispatch (type, payload) {
    const entry = this._actions[type]
    if (!entry) {
      console.error('unknow actions type')
    }
    entry(this, payload)
  }
}

function install (_Vue) {
  Vue = _Vue

  Vue.mixin({
    beforeCreate () {
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}

export default { Store, install }
